package com.deductive.common.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.geotools.geojson.geom.GeometryJSON;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.WKTWriter;

import java.io.IOException;
import java.io.StringReader;
import java.util.Map;

/**
 * 空间数据转换工具类 (Geometry <-> GeoJSON <-> WKB)
 */
public class GeometryUtils {

    private static final GeometryJSON gjson = new GeometryJSON();
    private static final ObjectMapper mapper = new ObjectMapper();
    private static final WKTWriter wktWriter = new WKTWriter();
    private static final WKBReader wkbReader = new WKBReader();

    /**
     * 将 JTS Geometry 对象转换为 GeoJSON 格式的 Map
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> geometryToGeoJsonMap(Geometry geometry) {
        if (geometry == null) {
            return null;
        }
        try {
            String geoJsonString = gjson.toString(geometry);
            return mapper.readValue(geoJsonString, Map.class);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Failed to convert Geometry to GeoJSON Map", e);
        }
    }

    /**
     * 将 GeoJSON 格式的 Map 转换为 WKT (Well-Known Text) 字符串
     */
    public static String geoJsonMapToWkt(Map<String, Object> geoJsonMap) {
        if (geoJsonMap == null || geoJsonMap.isEmpty()) {
            return null;
        }
        try {
            String geoJsonString = mapper.writeValueAsString(geoJsonMap);
            Geometry geometry = gjson.read(new StringReader(geoJsonString));
            return wktWriter.write(geometry);
        } catch (IOException e) {
            throw new RuntimeException("Failed to convert GeoJSON Map to WKT", e);
        }
    }

    /**
     * 将 WKB 十六进制字符串转换为 JTS Geometry 对象
     * @param wkbHex WKB 十六进制字符串
     * @return JTS Geometry 对象
     */
    public static Geometry wkbHexToGeometry(String wkbHex) {
        if (wkbHex == null || wkbHex.isEmpty()) {
            return null;
        }
        try {
            byte[] wkb = WKBReader.hexToBytes(wkbHex);
            return wkbReader.read(wkb);
        } catch (ParseException e) {
            throw new RuntimeException("Failed to parse WKB hex string to Geometry", e);
        }
    }
}
